
from enum import Enum
import os
import logging
import time
from hdc import Hdc
from uitest import UITest
from keycode import KeyCode

class ActionError(Exception):
    pass

class ActionType(Enum):
    SWIPE = "swipe"
    CLICK = "click"
    INPUT_TEXT = "input_text"
    DRAG = "drag"
    DUMPLAYOUT = "dump_layout"
    SCREEN_CAPTURE = "screen_capture"
    KEYEVENT = "keyevent"
    KEYEVENT_HOME = "keyevent_home"
    KEYEVENT_BACK = "keyevent_back"


class Action:
    """
    base action
    """
    def __init__(self):
        self.name: str = "base action"
        self.enable: bool = True
        self.interval: float = 100.0 / 1000.0
        self.count: int = 1

    def set_config(self, config: dict):
        self.enable = config.get("enable", True)
        self.interval = config.get("interval", 100) / 1000.0
        self.count = config.get("count", 1)
        return self
    
    def to_string(self) -> str:
        return f"""Action: {self.name}
        Enable: {self.enable}
        Interval: {self.interval}
        Count: {self.count}"""
    
    def execute(self, hdc: Hdc, device_id: str):
        pass

class SwipeAction(Action):
    """
    swipe action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.SWIPE.value
        self.begin_position: list = [0, 0]
        self.end_position: list = [0, 0]
        self.velocity: int = 600

    def set_config(self, config: dict) -> Action:
        super().set_config(config)
        self.begin_position = config.get("begin_position", [0, 0])
        self.end_position = config.get("end_position", [0, 0])
        self.velocity = config.get("velocity", 600)
        return self
    
    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute swipe action
        """
        if not self.enable:
            logging.info(f"Swipe action [name: {self.name}, from: {self.begin_position}, to: {self.end_position}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Swipe action [name: {self.name}, from: {self.begin_position}, to: {self.end_position}] count <= 0, skip")
            return
        operation = UITest.UIInput(hdc, device_id)
        for _ in range(self.count):
            operation.swipe(self.begin_position[0], self.begin_position[1], \
                            self.end_position[0], self.end_position[1], self.velocity)
            time.sleep(self.interval)

    
class ClickAction(Action):
    """
    click action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.CLICK.value
        self.type = 0  # click type, 0-click、1-longClick、2-doubleClick
        self.position = [0, 0]

    def set_config(self, config) -> Action:
        super().set_config(config)
        self.type = config.get("type", 0)
        self.position = config.get("position", [0, 0])
        return self
    
    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute click action
        """
        if not self.enable:
            logging.info(f"Click action [name: {self.name}, type: {self.type}, position: {self.position}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Click action [[name: {self.name}, type: {self.type}, position: {self.position}] count <= 0, skip")
            return
        operation = UITest.UIInput(hdc, device_id)
        for _ in range(self.count):
            if self.type == 0:
                operation.click(self.position[0], self.position[1])
            elif self.type == 1:
                operation.long_click(self.position[0], self.position[1])
            elif self.type == 2:
                operation.double_click(self.position[0], self.position[1])
            else:
                logging.error("unknown click type")
            time.sleep(self.interval)

class InputTextAction(Action):
    """
    input text action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.INPUT_TEXT.value
        self.text = ""
        self.position = [0, 0]

    def set_config(self, config) -> Action:
        super().set_config(config)
        self.text = config.get("text", "")
        self.position = config.get("position", [0, 0])
        return self
    
    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute input text action
        """
        if not self.enable:
            logging.info(f"Input text action [name: {self.name}, text: {self.text}, position: {self.position}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Input text action [name: {self.name}, text: {self.text}, position: {self.position}] count <= 0, skip")
            return
        operation = UITest.UIInput(hdc, device_id)
        for _ in range(self.count):
            operation.intput_text(self.position[0], self.position[1], self.text)
            time.sleep(self.interval)


class DragAction(Action):
    """
    drag action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.DRAG.value
        self.begin_position: list = [0, 0]
        self.end_position: list = [0, 0]
        self.velocity: int = 600

    def set_config(self, config: dict) -> Action:
        super().set_config(config)
        self.begin_position = config.get("begin_position", [0, 0])
        self.end_position = config.get("end_position", [0, 0])
        self.velocity = config.get("velocity", 600)
        return self
    
    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute drag action
        """
        if not self.enable:
            logging.info(f"Drag action [name: {self.name}, from: {self.begin_position}, to: {self.end_position}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Drag action [name: {self.name}, from: {self.begin_position}, to: {self.end_position}] count <= 0, skip")
            return
        operation = UITest.UIInput(hdc, device_id)
        for _ in range(self.count):
            operation.drag(self.begin_position[0], self.begin_position[1], \
                           self.end_position[0], self.end_position[1], self.velocity)
            time.sleep(self.interval)

class DumpLayoutAction(Action):
    """
    dump layout action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.DUMPLAYOUT.value
        self.local_path = "dumplayout"
    
    def set_config(self, config) -> Action:
        super().set_config(config)
        self.local_path = config.get("local_path", "dumplayout")
        return self

    def execute(self, hdc: Hdc, device_id: str):
        """
        execute dump layout action
        """
        if not self.enable:
            logging.info(f"Dump layout action [name: {self.name}, local path: {self.local_path}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Dump layout action [name: {self.name}, local path: {self.local_path}] count <= 0, skip")
            return
        operation = UITest.DumpLayout(hdc, device_id)
        for _ in range(self.count):
            if self.local_path != "": 
                path_tmp = os.path.realpath(self.local_path)
                if not os.path.exists(path_tmp):
                    os.makedirs(path_tmp)
                operation.dump_recv(self.local_path)
            else:
                operation.dump()
            time.sleep(self.interval)

class ScreenCaptureAction(Action):
    """
    screen capture action
    """
    def __init__(self):
        super().__init__()
        self.name = ActionType.SCREEN_CAPTURE.value
        self.local_path = "screenshots"

    def set_config(self, config) -> Action:
        super().set_config(config)
        self.local_path = config.get("local_path", "screenshots")
        return self
    
    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute screen capture action
        """
        if not self.enable:
            logging.info(f"Screen capture action [name: {self.name}, path: {self.local_path}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Screen capture action [name: {self.name}, path: {self.local_path}] count <= 0, skip")
            return
        operation = UITest.ScreenCapture(hdc, device_id)
        for _ in range(self.count):
            if self.local_path != "": 
                path_tmp = os.path.realpath(self.local_path)
                if not os.path.exists(path_tmp):
                    os.makedirs(path_tmp)
                operation.capture_recv(self.local_path)
            else:
                operation.capture()
            time.sleep(self.interval)

class KeyEventAction(Action):
    def __init__(self):
        super().__init__()
        self.name = "keyevent"
        self.keycode: KeyCode = KeyCode.KEYCODE_UNKNOWN

    def _enum_keycode(self, keycode_int: int) -> KeyCode:
        """
        get keycode
        """
        try:
            return KeyCode(self.keycode)
        except:
            raise ActionError(f"Keycode {self.keycode} not found")

    def set_config(self, config) -> Action:
        super().set_config(config)
        self.name = config.get("keyevent", "keyevent")
        keycode_int = config.get("keycode", -1)
        self.keycode = self._enum_keycode(keycode_int)
        return self

    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute input text action
        """
        if not self.enable:
            logging.info(f"Keyevent action [name: {self.name}, text: {self.keycode}] disable, skip")
            return
        if self.count <= 0:
            logging.info(f"Keyevent action [name: {self.name}, text: {self.keycode}] count <= 0, skip")
            return
        operation = UITest.UIInput(hdc, device_id)
        for _ in range(self.count):
            operation.key_event(self.keycode)
            time.sleep(self.interval)

class KeyEventHomeAction(KeyEventAction):
    def __init__(self):
        super().__init__()
        self.name = "keyevent_home"
        self.keycode = KeyCode.KEYCODE_HOME

    def set_config(self, config) -> Action:
        """
        set config
        """
        return self

    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute keyevent home action
        """
        logging.debug(f"Keyevent back action [name: {self.name}, keycode: {self.keycode}]")
        super().execute(hdc, device_id)

class KeyEventBackAction(KeyEventAction):
    def __init__(self):
        super().__init__()
        self.name = "keyevent_back"
        self.keycode = KeyCode.KEYCODE_BACK
    
    def set_config(self, config) -> Action:
        """
        set config
        """
        return self

    def execute(self, hdc: Hdc, device_id: str = ""):
        """
        execute keyevent back action
        """
        logging.debug(f"Keyevent back action [name: {self.name}, text: {self.keycode}]")
        super().execute(hdc, device_id)